﻿using Domain.Entitys.FG;
using Domain.Entitys.Inv;
using Domain.IRepositorys.FG;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EFCore.Repositorys.FG
{
    public class FG_Picking_OutboundRepository : IFG_Picking_OutboundRepository
    {
        private readonly MyDbContext myDbContext;

        public FG_Picking_OutboundRepository(MyDbContext myDbContext)
        {
            this.myDbContext = myDbContext;
        }
        /// <summary>
        /// 条件查询总条数
        /// </summary>
        /// <param name="Picking_outbound_code"></param>
        /// <param name="Warehouse_code"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public int GetFG_Picking_OutboundCount(string Picking_outbound_code, string Warehouse_code)
        {
            IQueryable<FG_Picking_Outbound> query = myDbContext.FG_Picking_Outbound.Where(d => d.Del_flag == '0');
            if (!string.IsNullOrEmpty(Picking_outbound_code))
            {
                query = query.Where(d => d.Picking_outbound_code.Contains(Picking_outbound_code));
            }
            if (!string.IsNullOrEmpty(Warehouse_code))
            {
                query = query.Where(d => d.Warehouse_code.Contains(Warehouse_code));
            }
            return query.Count();
        }
        /// <summary>
        /// 分页条件查询领料出库信息
        /// </summary>
        /// <param name="Picking_outbound_code"></param>
        /// <param name="Warehouse_code"></param>
        /// <param name="currentPage"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public List<FG_Picking_Outbound_Info> GetFG_Picking_OutboundFYwhere(string Picking_outbound_code, string Warehouse_code, int currentPage, int pageSize)
        {
            //return null;
            IQueryable<FG_Picking_Outbound> query = myDbContext.FG_Picking_Outbound.Where(d => d.Del_flag == '0').Include(d => d.Details).OrderBy(d => d.Picking_outbound_id).OrderByDescending(d => d.Create_time);
            if (!string.IsNullOrEmpty(Picking_outbound_code))
            {
                query = query.Where(d => d.Picking_outbound_code.Contains(Picking_outbound_code));
            }
            if (!string.IsNullOrEmpty(Warehouse_code))
            {
                query = query.Where(d => d.Warehouse_code.Contains(Warehouse_code));
            }
            var data = query.Skip((currentPage - 1) * pageSize).Take(pageSize).Select(d => new FG_Picking_Outbound_Info
            {
                Picking_outbound_id = d.Picking_outbound_id,
                Picking_outbound_code = d.Picking_outbound_code,
                Warehouse_code = d.Warehouse_code,
                Warehouse_name = d.Warehouse_name,
                Zone_code = d.Zone_code,
                Zone_name = d.Zone_name,
                Picking_outbound_time = d.Picking_outbound_time,
                Picking_outbound_rep_id = d.Picking_outbound_rep_id,
                Picking_outbound_dept_id = d.Picking_outbound_dept_id,
                Picking_outbound_status = d.Picking_outbound_status,
                Picking_outbound_audit_status = d.Picking_outbound_audit_status,
                Picking_outbound_audit_by = d.Picking_outbound_audit_by,
                Picking_outbound_audit_time = d.Picking_outbound_audit_time,
                Create_by = d.Create_by,
                Create_time = d.Create_time,
                Update_by = d.Update_by,
                Update_time = d.Update_time,
                Del_flag = d.Del_flag,
                Details = d.Details.Select(x => new FG_Picking_Outbound_Info.details
                {
                    Picking_outbound_details_id = x.Picking_outbound_details_id,
                    Picking_outbound_id = x.Picking_outbound_id,
                    Picking_outbound_code = x.Picking_outbound_code,
                    Pro_name = x.Pro_name,
                    Pro_code = x.Pro_code,
                    Pro_brand = x.Pro_brand,
                    Pro_model = x.Pro_model,
                    Measure_id = x.Measure_id,
                    Location_code = x.Location_code,
                    Location_name = x.Location_name,
                    Pro_attribute_id = x.Pro_attribute_id,
                    Picking_outbound_qty = x.Picking_outbound_qty,
                    Picking_for_outbound_qty = x.Picking_for_outbound_qty
                }).ToList()
            }).ToList();
            return data;
        }

        /// <summary>
        /// 添加、增加库存预计出库数量
        /// </summary>
        /// <param name="fG_Picking_Outbound"></param>
        /// <param name="fg_Picking_Outbound_Details"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<int> PutFG_Picking_OutboundAdd(FG_Picking_Outbound fG_Picking_Outbound, List<Fg_Picking_Outbound_Details> fg_Picking_Outbound_Details)
        {
            using var transaction = await myDbContext.Database.BeginTransactionAsync();
            try
            {
                // 1. 添加拣货出库主表
                await myDbContext.AddAsync(fG_Picking_Outbound);
                await myDbContext.SaveChangesAsync();

                // 2. 设置明细关联ID并添加明细
                foreach (var detail in fg_Picking_Outbound_Details)
                {
                    detail.Picking_outbound_id = fG_Picking_Outbound.Picking_outbound_id;
                    detail.Picking_outbound_code = fG_Picking_Outbound.Picking_outbound_code;
                }
                await myDbContext.Fg_Picking_Outbound_Details.AddRangeAsync(fg_Picking_Outbound_Details);
                await myDbContext.SaveChangesAsync();

                // 3. 更新库存中的可用数量
                foreach (var detail in fg_Picking_Outbound_Details)
                {
                    // 查询所有匹配的库存记录
                    var stocks = await myDbContext.inv_stock
                        .Where(s => s.pro_code == detail.Pro_code &&
                        s.Warehouse_Code == fG_Picking_Outbound.Warehouse_code &&
                        s.Zone_Code == fG_Picking_Outbound.Zone_code &&
                        s.Location_Code == detail.Location_code)
                        .ToListAsync();

                    //s.Location_Code == fG_Picking_Outbound
                    // 检查库存记录数量
                    if (stocks.Count == 0)
                    {
                        throw new Exception($"库存记录不存在: 产品编码 {detail.Pro_code}");
                    }
                    //else if (stocks.Count > 1)
                    //{
                    //    throw new Exception($"存在多条库存记录: 产品编码 {detail.Pro_code}，请检查库存唯一性");
                    //}

                    // 获取唯一库存记录
                    var stock = stocks.First();

                    // 检查库存是否足够
                    if (stock.stock_numder < detail.Picking_outbound_qty)
                    {
                        throw new Exception($"库存不足: 产品编码 {detail.Pro_code}，可用数量 {stock.stock_numder - stock.Stock_planned_outbound_qty}，需求数量 {detail.Picking_outbound_qty}");
                    }

                    // 更新库存可用数量和锁定数量
                    stock.Stock_planned_outbound_qty += detail.Picking_outbound_qty;
                }

                // 4. 保存所有更改
                await myDbContext.SaveChangesAsync();
                await transaction.CommitAsync();
                return 1;
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync();
                // 记录日志或处理异常
                throw new DbUpdateException("拣货出库单添加失败，已回滚", ex);
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="fG_Picking_Outbound"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<int> PutFG_Picking_OutboundDelete(FG_Picking_Outbound fG_Picking_Outbound)
        {
            using var transaction = await myDbContext.Database.BeginTransactionAsync();
            try
            {
                // 1. 获取领料出库单及其明细
                var fg = await myDbContext.FG_Picking_Outbound
                    .Include(p => p.Details)
                    .FirstOrDefaultAsync(p => p.Picking_outbound_id == fG_Picking_Outbound.Picking_outbound_id);

                if (fg == null)
                {
                    throw new KeyNotFoundException($"找不到ID为 {fG_Picking_Outbound.Picking_outbound_id} 的领料出库单");
                }

                // 2. 恢复库存待出库数量
                foreach (var detail in fg.Details)
                {
                    // 查询所有匹配的库存记录
                    var stocks = await myDbContext.inv_stock
                        .Where(s => s.pro_code == detail.Pro_code &&
                                    s.Warehouse_Code == fg.Warehouse_code &&
                                    s.Zone_Code == fg.Zone_code &&
                                    s.Location_Code == detail.Location_code)
                        .ToListAsync();

                    // 检查库存记录数量
                    if (stocks.Count == 0)
                    {
                        throw new Exception($"库存记录不存在: 产品编码 {detail.Pro_code}");
                    }

                    // 获取库存记录（取第一条）
                    var stock = stocks.First();

                    // 检查库存是否足够恢复
                    if (stock.Stock_planned_outbound_qty < detail.Picking_outbound_qty)
                    {
                        throw new Exception($"库存待出库数量不足: 产品编码 {detail.Pro_code}，当前待出库数量 {stock.Stock_planned_outbound_qty}，需要恢复数量 {detail.Picking_outbound_qty}");
                    }

                    // 恢复库存待出库数量
                    stock.Stock_planned_outbound_qty -= detail.Picking_outbound_qty;
                }

                // 3. 逻辑删除领料出库单
                fg.Del_flag = fG_Picking_Outbound.Del_flag;
                myDbContext.Entry(fg).State = EntityState.Modified;

                // 4. 保存所有更改
                await myDbContext.SaveChangesAsync();

                // 5. 提交事务
                await transaction.CommitAsync();

                return 1; // 返回成功标志
            }
            catch (Exception ex)
            {
                // 6. 回滚事务
                await transaction.RollbackAsync();

                // 记录日志或处理异常
                throw new DbUpdateException("领料出库单删除失败，已回滚", ex);
            }
        }
        /// <summary>
        /// 查询库存信息
        /// </summary>
        /// <param name="Warehouse_Code"></param>
        /// <param name="Zone_Code"></param>
        /// <param name="pro_code"></param>
        /// <param name="pro_attribute_id"></param>
        /// <param name="currentPage"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<List<inv_stock>> GetInv_StockAsyncs(string Warehouse_Code, string Zone_Code, string pro_code, int pro_attribute_id, int currentPage, int pageSize)
        {
            var query = myDbContext.inv_stock.Where(s => s.Del_Flag == '0');
            if (!string.IsNullOrEmpty(Warehouse_Code))
            {
                query = query.Where(s => s.Warehouse_Code.Contains(Warehouse_Code));
            }
            if (!string.IsNullOrEmpty(Zone_Code))
            {
                query = query.Where(s => s.Zone_Code.Contains(Zone_Code));
            }
            if (!string.IsNullOrEmpty(pro_code))
            {
                query = query.Where(s => s.pro_code.Contains(pro_code) || s.stock_name.Contains(pro_code));
            }
            if (pro_attribute_id > 0)
            {
                query = query.Where(s => s.Pro_attribute_id == pro_attribute_id);
            }

            return await query.Skip((currentPage - 1) * pageSize).Take(pageSize).ToListAsync();
        }
        /// <summary>
        /// 查询库存信息总条数
        /// </summary>
        /// <param name="Warehouse_Code"></param>
        /// <param name="Zone_Code"></param>
        /// <param name="pro_code"></param>
        /// <param name="pro_attribute_id"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<int> Inv_StockCountAsyncs(string Warehouse_Code, string Zone_Code, string pro_code, int pro_attribute_id)
        {
            var query = myDbContext.inv_stock.Where(s => s.Del_Flag == '0');
            if (!string.IsNullOrEmpty(Warehouse_Code))
            {
                query = query.Where(s => s.Warehouse_Code.Contains(Warehouse_Code));
            }
            if (!string.IsNullOrEmpty(Zone_Code))
            {
                query = query.Where(s => s.Zone_Code.Contains(Zone_Code));
            }
            if (!string.IsNullOrEmpty(pro_code))
            {
                query = query.Where(s => s.pro_code.Contains(pro_code) || s.stock_name.Contains(pro_code));
            }
            if (pro_attribute_id > 0)
            {
                query = query.Where(s => s.Pro_attribute_id == pro_attribute_id);
            }
            return await query.CountAsync();
        }
        /// <summary>
        /// 修改领料出库及其明细、库存待出库量等
        /// </summary>
        /// <param name="fG_Picking_Outbound"></param>
        /// <param name="fg_Picking_Outbound_Details"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<int> PutFg_Picking_OutboundUpdate(FG_Picking_Outbound fG_Picking_Outbound, List<Fg_Picking_Outbound_Details> fg_Picking_Outbound_Details)
        {
            using var transaction = await myDbContext.Database.BeginTransactionAsync();
            try
            {
                //1.更新主表信息
                var fg = await myDbContext.FG_Picking_Outbound.FirstOrDefaultAsync(d => d.Picking_outbound_id == fG_Picking_Outbound.Picking_outbound_id);
                if (fg == null)
                {
                    return 0;
                }

                // 更新主表字段...
                fg.Picking_outbound_time = fG_Picking_Outbound.Picking_outbound_time;
                fg.Picking_outbound_id = fG_Picking_Outbound.Picking_outbound_id;
                fg.Picking_outbound_code = fG_Picking_Outbound.Picking_outbound_code;
                fg.Warehouse_code = fG_Picking_Outbound.Warehouse_code;
                fg.Warehouse_name = fG_Picking_Outbound.Warehouse_name;
                fg.Zone_code = fG_Picking_Outbound.Zone_code;
                fg.Zone_name = fG_Picking_Outbound.Zone_name;
                fg.Picking_outbound_rep_id = fG_Picking_Outbound.Picking_outbound_rep_id;
                fg.Picking_outbound_dept_id = fG_Picking_Outbound.Picking_outbound_dept_id;
                fg.Update_by = fG_Picking_Outbound.Update_by;
                fg.Update_time = fG_Picking_Outbound.Update_time;
                myDbContext.Update(fg);
                await myDbContext.SaveChangesAsync();

                //2.获取旧明细数据
                var fgdetails = await myDbContext.Fg_Picking_Outbound_Details
                    .Where(d => d.Picking_outbound_code == fg.Picking_outbound_code)
                    .AsNoTracking()
                    .ToListAsync();

                //3.更新明细数据
                //3.1识别三类记录
                var fgAdd = new List<Fg_Picking_Outbound_Details>();
                var fgUpdate = new List<Fg_Picking_Outbound_Details>();
                var fgDelete = new List<Fg_Picking_Outbound_Details>(); // 改为存储实体对象而非ID

                //遍历传入的新明细列表
                foreach (var newItem in fg_Picking_Outbound_Details)
                {
                    // 3.2 新记录：无主键或主键不在旧列表中
                    if (newItem.Picking_outbound_details_id == 0 || !fgdetails.Any(d => d.Picking_outbound_details_id == newItem.Picking_outbound_details_id))
                    {
                        fgAdd.Add(newItem);
                    }
                    //修改
                    else
                    {
                        var fgitem = fgdetails.First(d => d.Picking_outbound_details_id == newItem.Picking_outbound_details_id);
                        if (IsUpdate(fgitem, newItem))
                        {
                            fgUpdate.Add(newItem);
                        }
                    }
                }

                //3.3删除 - 找出需要删除的旧明细
                fgDelete = fgdetails
                    .Where(d => !fg_Picking_Outbound_Details.Any(newItem => newItem.Picking_outbound_details_id == d.Picking_outbound_details_id))
                    .ToList();

                //4.执行差异化操作
                //4.1删除被移除的数据（先处理库存）
                if (fgDelete.Any())
                {
                    foreach (var deleteItem in fgDelete)
                    {
                        // 更新库存
                        var stocks = await myDbContext.inv_stock
                            .Where(s => s.pro_code == deleteItem.Pro_code &&
                            s.Warehouse_Code == fg.Warehouse_code &&
                            s.Zone_Code == fg.Zone_code &&
                            s.Location_Code == deleteItem.Location_code)
                            .ToListAsync();

                        if (stocks.Any())
                        {
                            var stock = stocks.First();
                            stock.Stock_planned_outbound_qty -= deleteItem.Picking_outbound_qty;
                        }
                    }

                    // 从数据库中删除
                    myDbContext.RemoveRange(fgDelete);
                }

                //4.2更新变化的明细
                foreach (var item in fgUpdate)
                {
                    var oldItem = fgdetails.First(d => d.Picking_outbound_details_id == item.Picking_outbound_details_id);

                    // 如果数量有变化，更新库存
                    if (oldItem.Picking_outbound_qty != item.Picking_outbound_qty)
                    {
                        var stocks = await myDbContext.inv_stock
                            .Where(s => s.pro_code == item.Pro_code &&
                            s.Warehouse_Code == fg.Warehouse_code &&
                            s.Zone_Code == fg.Zone_code &&
                            s.Location_Code == item.Location_code)

                            .ToListAsync();

                        if (stocks.Any())
                        {
                            var stock = stocks.First();
                            // 计算差值并更新
                            var diff = item.Picking_outbound_qty - oldItem.Picking_outbound_qty;
                            stock.Stock_planned_outbound_qty += diff;

                            // 检查库存是否足够
                            if (stock.stock_numder < stock.Stock_planned_outbound_qty)
                            {
                                throw new Exception($"库存不足: 产品编码 {item.Pro_code}，可用数量 {stock.stock_numder - stock.Stock_planned_outbound_qty + diff}，需求数量 {diff}");
                            }
                        }
                    }

                    myDbContext.Entry(item).State = EntityState.Modified;
                }

                //4.3新增明细
                foreach (var item in fgAdd)
                {
                    item.Picking_outbound_id = fg.Picking_outbound_id;//设置外键
                    item.Picking_outbound_code = fg.Picking_outbound_code;
                    await myDbContext.AddAsync(item);

                    // 更新库存
                    var stocks = await myDbContext.inv_stock
                        .Where(s => s.pro_code == item.Pro_code &&
                        s.Warehouse_Code == fg.Warehouse_code &&
                        s.Zone_Code == fg.Zone_code)
                        .ToListAsync();

                    if (stocks.Any())
                    {
                        var stock = stocks.First();
                        stock.Stock_planned_outbound_qty += item.Picking_outbound_qty;

                        // 检查库存是否足够
                        if (stock.stock_numder < stock.Stock_planned_outbound_qty)
                        {
                            throw new Exception($"库存不足: 产品编码 {item.Pro_code}，可用数量 {stock.stock_numder - stock.Stock_planned_outbound_qty + item.Picking_outbound_qty}，需求数量 {item.Picking_outbound_qty}");
                        }
                    }
                }

                await myDbContext.SaveChangesAsync();
                await transaction.CommitAsync();
                return 1;
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync();
                throw new DbUpdateException("拣货出库单更新失败，已回滚", ex);
            }
        }
        /// <summary>
        /// 验证明细中的值是否更改
        /// </summary>
        /// <param name="fgItem"></param>
        /// <param name="newItem"></param>
        /// <returns></returns>
        private bool IsUpdate(Fg_Picking_Outbound_Details fgItem, Fg_Picking_Outbound_Details newItem)
        {
            return fgItem.Picking_outbound_qty != newItem.Picking_outbound_qty || fgItem.Location_code != newItem.Location_code || fgItem.Location_name != newItem.Location_name;
        }
        /// <summary>
        /// 审核
        /// </summary>
        /// <param name="fG_Picking_Outbound"></param>
        /// <param name="fg_Picking_Outbound_Details"></param>
        /// <returns></returns>
        public async Task<int> PutFg_Picking_OutboundAudit(FG_Picking_Outbound fG_Picking_Outbound, List<Fg_Picking_Outbound_Details> fg_Picking_Outbound_Details)
        {
            using var transaction = await myDbContext.Database.BeginTransactionAsync();
            try
            {
                // 1. 更新主表审核状态
                var mainEntity = await myDbContext.FG_Picking_Outbound
                    .FirstOrDefaultAsync(x => x.Picking_outbound_id == fG_Picking_Outbound.Picking_outbound_id);

                if (mainEntity == null)
                {
                    throw new Exception($"拣货出库单不存在，ID: {fG_Picking_Outbound.Picking_outbound_id}");
                }

                if (fG_Picking_Outbound.Picking_outbound_audit_status == '1')
                {
                    //mainEntity.Picking_outbound_audit_status = fG_Picking_Outbound.Picking_outbound_audit_status
                    mainEntity.Picking_outbound_audit_status = fG_Picking_Outbound.Picking_outbound_audit_status;
                    mainEntity.Picking_outbound_audit_by = fG_Picking_Outbound.Picking_outbound_audit_by;
                    mainEntity.Picking_outbound_audit_time = DateTime.Now;
                    mainEntity.Picking_outbound_status = '1';

                    // 2. 更新明细表中的出库数量和待出库数量
                    var detailIds = fg_Picking_Outbound_Details.Select(x => x.Picking_outbound_details_id).ToList();
                    var details = await myDbContext.Fg_Picking_Outbound_Details
                        .Where(x => x.Picking_outbound_id == fG_Picking_Outbound.Picking_outbound_id &&
                                    detailIds.Contains(x.Picking_outbound_details_id))
                        .ToListAsync();

                    foreach (var detail in details)
                    {
                        var inputDetail = fg_Picking_Outbound_Details
                            .FirstOrDefault(x => x.Picking_outbound_details_id == detail.Picking_outbound_details_id);

                        if (inputDetail != null)
                        {
                            // 将待出库数量加到出库数量上
                            detail.Picking_for_outbound_qty += detail.Picking_outbound_qty;
                            // 清零待出库数量
                            //detail.Picking_outbound_qty = 0;
                        }
                    }

                    // 3. 更新库存中的锁定数量和实际数量
                    foreach (var detail in details)
                    {
                        // 查询所有匹配的库存记录
                        var stocks = await myDbContext.inv_stock
                            .Where(s => s.pro_code == detail.Pro_code &&
                                       s.Warehouse_Code == mainEntity.Warehouse_code &&
                                       s.Zone_Code == mainEntity.Zone_code &&
                                       s.Location_Code == detail.Location_code)
                            .ToListAsync();

                        if (stocks.Count == 0)
                        {
                            throw new Exception($"库存记录不存在: 产品编码 {detail.Pro_code}");
                        }

                        var stock = stocks.First();

                        // 检查锁定数量是否足够
                        if (stock.Stock_planned_outbound_qty < detail.Picking_outbound_qty)
                        {
                            throw new Exception($"锁定库存不足: 产品编码 {detail.Pro_code}，锁定数量 {stock.Stock_planned_outbound_qty}，出库数量 {detail.Picking_outbound_qty}");
                        }

                        // 更新库存：减少锁定数量，减少实际数量
                        stock.Stock_planned_outbound_qty -= detail.Picking_outbound_qty;
                        stock.stock_numder -= detail.Picking_outbound_qty;
                        detail.Picking_outbound_qty = 0;
                    }

                    // 4. 保存所有更改
                    await myDbContext.SaveChangesAsync();
                    await transaction.CommitAsync();
                    return 1;
                }
                else
                {
                    mainEntity.Picking_outbound_audit_status = fG_Picking_Outbound.Picking_outbound_audit_status;
                    mainEntity.Picking_outbound_audit_by = fG_Picking_Outbound.Picking_outbound_audit_by;
                    mainEntity.Picking_outbound_audit_time = DateTime.Now;
                    mainEntity.Picking_outbound_status = '1';
                    await myDbContext.SaveChangesAsync();
                    await transaction.CommitAsync();
                    return 1;
                }
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync();
                // 记录日志或处理异常
                throw new DbUpdateException("拣货出库单审核失败，已回滚", ex);
            }
        }
    }
}
